package com.readaloud.hibernate.user;


import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;

import com.readaloud.indexing.KeyWord;

@Entity
public class Books implements Serializable{
	
	public Books(){
		
	}
	@Id @GeneratedValue(strategy = GenerationType.AUTO)
	private int bookId;
	
	//@OneToMany
	//private Collection<KeyWord> keyword = new ArrayList<KeyWord>();
	
	private String name;
	private String location; // file,url
	private Date date;
	private long numWords;
	private String title;
	private String author;
	private String language;
	private String publishDate;
	
	@OneToOne
	private BookClub bookClub;
	// may want to count the words to know the strength of a word within a
	// document. Also, separation (distance between words) can give us other
	// metrics on the keywords
	
	
	@OneToMany(cascade = CascadeType.ALL,fetch=FetchType.EAGER)
	private Map<String, KeyWord> keywords = new HashMap<String, KeyWord>();
	//@Id
	//private HashMap<String, KeyWord> docIDs = new HashMap<String, KeyWord>();

	@OneToMany(mappedBy = "books",cascade= CascadeType.ALL)
	@NotFound(action = NotFoundAction.IGNORE)
	private Collection<Comment> comment = new ArrayList<Comment>();
	
	@ManyToOne
	@JoinColumn(name = "userId")
	@NotFound(action = NotFoundAction.IGNORE)
	private Author authorObject;
	
	public int getBookId() {
		return bookId;
	}

	public void setBookId(int bookId) {
		this.bookId = bookId;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}


	public Map<String, KeyWord> getKeywords() {
		return keywords;
	}

	public void setKeywords(Map<String, KeyWord> keywords) {
		this.keywords = keywords;
	}

	public Books(File f) {
		if (f == null)
			return;

		location = f.getAbsolutePath();
		name = f.getName();
		date = new Date(f.lastModified());
	}

/*	*//**
	 * collect keywords by frequency
	 * 
	 * TODO use a euclidean distance for weighting word importance => clustering
	 * 
	 * @param w
	 *//*
	public void addKeyword(String w, int position) {
		if (w == null || w.trim().length() == 0)
			return;
		else {
			KeyWord kw = keywords.get(w.trim().toLowerCase());
			if (kw == null) {
				kw = new KeyWord(w.trim().toLowerCase(), position);
				keywords.put(kw.word, kw);
			} else
				kw.add(position);
		}

	}

	*//**
	 * Examines if the two documents share keywords and returns a intersection
	 * value (0-1.0) uses a weighted jaccard index by including the frequency of
	 * word occurrences
	 * 
	 * @param doc
	 * @return
	 *//*
	public double similarity(Books doc) {
		if (keywords == null || doc.keywords == null)
			return 0.0;

		int total = 0, count = 0;
		if (keywords.size() > doc.keywords.size()) {
			for (KeyWord kw : keywords.values()) {
				total += kw.position.size();
				if (doc.keywords.containsKey(kw.word))
					count += kw.position.size();
			}
		} else {
			for (KeyWord kw : doc.keywords.values()) {
				total += kw.position.size();
				if (keywords.containsKey(kw.word))
					count += kw.position.size();
			}
		}

		// jaccard weighted index
		double r = (double) count / (double) total;

		// rounding
		int ri = (int) (r * 10000.0f);
		r = ((double) ri) / 10000.0f;
		return r;
	}

	*//**
	 * ordered list of keywords by frequency of occurrence
	 * 
	 * @return
	 *//*
	public List<KeyWord> keywords() {
		List<KeyWord> list = new ArrayList<KeyWord>(keywords.values());
		Collections.sort(list, new Comparator<KeyWord>() {

			@Override
			public int compare(KeyWord w1, KeyWord w2) {
				if (w1.position.size() == w2.position.size())
					return 0;
				else if (w1.position.size() < w2.position.size())
					return 1;
				else
					return -1;
			}
		});

		return list;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("Name: ");
		sb.append(name);
		sb.append("\nFile: ");
		sb.append(location);
		sb.append("\nNum words: ");
		sb.append(numWords);
		sb.append("\nKeywords:\n");

		DecimalFormat fmt = new DecimalFormat("#.##");

		for (KeyWord kw : keywords()) {
			sb.append(kw.word);
			sb.append(" (n = ");
			sb.append(kw.position.size());
			sb.append(", pos = [");

			double ave = 0.0f;
			for (Integer p : kw.position) {
				ave += p;
				sb.append(p);
				sb.append(",");
			}
			sb.deleteCharAt(sb.length() - 1);
			sb.append("], ");

			ave /= kw.position.size();
			sb.append("mean = ");
			sb.append(fmt.format(ave));
			sb.append(", stdev = ");
			sb.append(fmt.format(kw.stdDev()));
			sb.append(")\n");

		}
		return sb.toString();
	}

	public String csvHeader() {
		StringBuilder sb = new StringBuilder();
		sb.append("name,location,numWords\n");
		sb.append("\"");
		sb.append(name);
		sb.append("\",\"");
		sb.append(location);
		sb.append("\",");
		sb.append(numWords);
		sb.append("\n");

		return sb.toString();
	}

	public String csvData() {
		StringBuilder sb = new StringBuilder();
		sb.append("\n\n");
		sb.append("word, freq, pos (mean), pos (stdev)\n");

		DecimalFormat fmt = new DecimalFormat("#.##");

		for (KeyWord kw : keywords()) {
			double ave = 0.0f;
			for (Integer p : kw.position) {
				ave += p;
			}
			ave /= kw.position.size();

			sb.append("\"");
			sb.append(kw.word);
			sb.append("\",");
			sb.append(kw.position.size());
			sb.append(",");
			sb.append(fmt.format(ave));
			sb.append(",");
			sb.append(fmt.format(kw.stdDev()));
			sb.append("\n");

		}
		return sb.toString();
	}*/

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public long getNumWords() {
		return numWords;
	}

	public void setNumWords(long numWords) {
		this.numWords = numWords;
	}

	public Collection<Comment> getComment() {
		return comment;
	}

	public void setComment(Collection<Comment> comment) {
		this.comment = comment;
	}
	
	//function to parse book for details

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}
		
	public String getBookAuthor() {
		return author;
	}

	public void setBookAuthor(String bookAuthor) {
		this.author = bookAuthor;
	}

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	public String getReleaseDate() {
		return publishDate;
	}

	public void setReleaseDate(String releaseDate) {
		this.publishDate = releaseDate;
	}

/*	public void parsebook(File filepath)
	{
		FileInputStream fstream;
		try {
			//if (filepath.isFile()) {
				fstream = new FileInputStream(filepath);

				DataInputStream in = new DataInputStream(fstream);
				BufferedReader br = new BufferedReader(
						new InputStreamReader(in));
				String strLine;
				String[] temp = null;

				while ((strLine = br.readLine()) != null) {

					if (strLine.contains("Title:")) {
						temp = strLine.split(":");
						strLine = temp[1].trim();
						// set in object value setTitle();

						System.out.println("T->" + strLine);
						this.setTitle(strLine);
						temp = null;
					}
					if (strLine.contains("Author:")) {
						temp = strLine.split(":");
						strLine = temp[1].trim();
						// set in object to persist
						System.out.println("A->" + strLine);
						this.setBookAuthor(strLine);
						temp = null;
					}

					if (strLine.contains("Release Date:")) {
						temp = strLine.split(":");
						strLine = temp[1].trim();
						// System.out.println("temp check" + strLine);
						temp = strLine.split("\\[");
						strLine = temp[0].trim();

						// set object
						System.out.println("R->" + strLine);
						this.setReleaseDate(strLine);
						temp = null;	
					}

					if (strLine.contains("Language:")) {
						temp = strLine.split(":");
						strLine = temp[1].trim();

						// set object
						System.out.println("L->" + strLine);
						this.setLanguage(strLine);
						temp = null;
						break;
					}

				}
			//}
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			
			if(obj.getfield is null)
				set that object field to "data not available"
				
				and then persist
		}

	}*/

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public String getPublishDate() {
		return publishDate;
	}

	public void setPublishDate(String publishDate) {
		this.publishDate = publishDate;
	}

	public BookClub getBookClub() {
		return bookClub;
	}

	public void setBookClub(BookClub bookClub) {
		this.bookClub = bookClub;
	}

	public Author getAuthorObject() {
		return authorObject;
	}

	public void setAuthorObject(Author authorObject) {
		this.authorObject = authorObject;
	}

}
